import numpy

from classfile.class_reader import ByteReader
from classfile.constant import ConstantPool
from utils.numer_utils import math


class ExceptionTable:

    def __init__(self, startPc, endPc, handlerPc, catchType):
        # 异常抛出的 指令序号
        self.startPc: numpy.uint16 = startPc
        # 异常终止的 指令序号
        self.endPc: numpy.uint16 = endPc
        # 指定的地址进行异常处理
        self.handlerPc: numpy.uint16 = handlerPc
        # 表示此异常处理条目所能捕获的异常类型。它可能是一个标识符，用于区分不同的异常种类
        self.catchType: numpy.uint16 = catchType

    def getCatchType(self):
        return self.catchType

    def getStartPc(self):
        return self.startPc

    def getEndPc(self):
        return self.endPc

    def getHandlerPc(self):
        return self.handlerPc







class LineNumber:
    def __init__(self, startPc, lineNo):
        self.startPc: numpy.uint16 = startPc
        self.lineNo: numpy.uint16 = lineNo


class LocalVariableTableInfo:

    def __init__(self, startPc, length, localVariableNameIndex
                 , localVariableName, localVariableDescriptorIndex
                 , localVariableDescriptor, localVariableIndex
                 ):
        # 变量开始生效的行
        self.startPc: numpy.uint16 = startPc
        # 变量影响范围
        self.length: numpy.uint16 = length
        self.localVariableNameIndex: numpy.uint16 = localVariableNameIndex
        # 变量名称
        self.LocalVariableName = localVariableName
        self.localVariableDescriptorIndex: numpy.uint16 = localVariableDescriptorIndex
        self.localVariableDescriptor = localVariableDescriptor
        self.localVariableIndex: numpy.uint16 = localVariableIndex


class LocalVarTypeTableInfo:

    def __init__(self, br: ByteReader, cp: ConstantPool):
        self.startPc: numpy.uint16 = br.readUInt16()
        self.length: numpy.uint16 = br.readUInt16()
        self.localVarTypeNameIndex = br.readUInt16()
        self.localVarTypeName = cp.getConstant(index=self.localVarTypeNameIndex)
        self.signatureIndex: numpy.uint16 = br.readUInt16()
        self.signature = cp.getConstant(index=int(self.signatureIndex))
        self.localVarTypeIndex = br.readUInt16()


class AnnotationPair:

    def __init__(self, br: ByteReader):
        self.pairIndex: numpy.uint16 = br.readUInt16()
        self.pairValue = None
        if self.pairIndex == 0x0000:
            self.pairValue = numpy.int8(br.readUInt8())
        elif self.pairIndex == 0x0001:
            self.pairValue = chr(br.readUInt8())
        elif self.pairIndex == 0x0002:
            self.pairValue = math.bit_to_float64(br.readUInt64())
        elif self.pairIndex == 0x0003:
            self.pairValue = math.bit_to_float32(br.readUInt32())
        elif self.pairIndex == 0x0004:
            self.pairValue = numpy.int32(br.readUInt32())
        elif self.pairIndex == 0x0005:
            self.pairValue = numpy.int64(br.readUInt64())
        elif self.pairIndex == 0x0006:
            self.pairValue = numpy.int16(br.readUInt16())
        elif self.pairIndex == 0x0007:
            self.pairValue = (br.readUInt8() & 0x01 != 0)
        else:
            # return fmt.Sprintf("%v", string(data.GetPos()))
            print("not support type for anno:{}", self.pairIndex)
            self.pairValue = str(br.pos)


class Annotation:

    def __init__(self, br: ByteReader):
        self.typeIndex: numpy.uint16 = br.readUInt16()
        self.pairNum: numpy.uint16 = br.readUInt16()
        self.pairs = []
        if self.pairNum > 0:
            for i in range(0, self.pairNum):
                self.pairs.append(AnnotationPair(br=br))


class InnerClass:

    def __init__(self, br: ByteReader):
        self.InnerClassInfoIndex: numpy.uint16 = br.readUInt16()
        self.OuterClassInfoIndex: numpy.uint16 = br.readUInt16()
        self.InnerNameIndex: numpy.uint16 = br.readUInt16()
        self.innerClassAccessFlags: numpy.uint16 = br.readUInt16()
